package com.ytjj.qmyx.users.service.impl;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.ytjj.common.api.CommonResult;
import com.ytjj.common.api.ResultCode;
import com.ytjj.common.constants.QueueConstants;
import com.ytjj.common.dto.mqdto.SmsDto;
import com.ytjj.common.exception.ApiException;
import com.ytjj.common.model.SanTongResponse;
import com.ytjj.common.model.XinycSmsResponse;
import com.ytjj.common.utils.DateTimeUtil;
import com.ytjj.common.utils.EncryptUtil;
import com.ytjj.common.utils.IPUtil;
import com.ytjj.common.utils.TokenUtil;
import com.ytjj.common.utils.feishu.FeiShuUtil;
import com.ytjj.qmyx.users.config.SanTongApiConfig;
import com.ytjj.qmyx.users.constants.SmsConstant;
import com.ytjj.qmyx.users.dao.MsgDao;
import com.ytjj.qmyx.users.dao.OrdersDao;
import com.ytjj.qmyx.users.dao.UsersDao;
import com.ytjj.qmyx.users.enums.SmsTypeEnums;
import com.ytjj.qmyx.users.mapper.UsersMapper;
import com.ytjj.qmyx.users.mapper.UsersMsgMapper;
import com.ytjj.qmyx.users.model.Users;
import com.ytjj.qmyx.users.model.UsersMsg;
import com.ytjj.qmyx.users.service.RedisService;
import com.ytjj.qmyx.users.service.SmsService;
import com.ytjj.qmyx.users.utils.DateUtils;
import com.ytjj.qmyx.users.utils.PhoneFormatCheckUtils;
import com.ytjj.qmyx.users.utils.SmsWayUtil;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import static org.apache.commons.lang.RandomStringUtils.randomNumeric;

/**
 * 短信接口实现
 *
 *
 * @version 1.0
 *
 */
@Service
@Slf4j
@RefreshScope
public class SmsServiceImpl implements SmsService {


    private final RedisService redisService;
    @Resource
    private  UsersMsgMapper usersMsgMapper;
    @Resource
    private MsgDao msgDao;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private SanTongApiConfig sanTongApiConfig;
    @Resource
    private OrdersDao ordersDao;
    @Resource
    private RedissonClient redissonClient;

    @Value("${sms.switch}")
    private String smsSwitch;
    /**
     * 发送方式
     * 1=mq  2=thread
     */
    @Value("${sms.send.type:1}")
    private Integer smsSendType;
    /**
     * 是否根据ip来限制验证码发送
     * 1=限制  2=不限制
     */
    @Value("${sms.send.limitIpFlag:2}")
    private Integer limitIpFlag;
    /**
     * 发送短信通道
     * santong：欣易辰
     */
    @Value("${sms.channel:xinyichen}")
    private String smsChannel;

    @Value("${sms.sign:【XXXX优品】}")
    private String sign;

    @Resource
    private UsersDao usersDao;

    public SmsServiceImpl(RedisService redisService) {
        this.redisService = redisService;
    }

    ThreadFactory springThreadFactory = new CustomizableThreadFactory("sms-pool-");
    ThreadPoolExecutor pools = new ThreadPoolExecutor(10,
            50,
            5,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(1024 * 1024),
            springThreadFactory);
    @Override
    public CommonResult generateAuthCode(String telephone, String type) {
        AtomicReference<String> authCode = new AtomicReference<>("666666");
        boolean checkResult = PhoneFormatCheckUtils.isPhoneLegal(telephone);
        if (!checkResult) {
            throw new ApiException(ResultCode.PHONE_IS_ERR_FORMAT);
        }
        if(smsSwitch.equals("true")){
            RLock lock = redissonClient.getLock("verificationCodeLock:"+ type + telephone);
            try {
                boolean b = lock.tryLock(0, 5, TimeUnit.SECONDS);
                if(!b){
                    log.info("=======当前锁未释放======");
                    return CommonResult.failed(ResultCode.FREQUENT_REQUESTS);
                }
//                if ("loginPhone".equals(type)) {
//                    //校验手机号,是否下过单
//                    Integer integer = ordersDao.orderNumByTel(telephone);
//                    if (integer == 0) {
//                        return CommonResult.failed(ResultCode.NO_USER.getMessage());
//                    }
//                    // 查询60分钟内发送短信的数量
//                    Map<String,Object> msgInfo = queryMsgCountByTel(telephone);
//                    if (!CollectionUtils.isEmpty(msgInfo)) {
//                        Long latestTime = msgInfo.get("latestTime") == null ? null : Long.valueOf(msgInfo.get("latestTime").toString());
//                        Integer total = msgInfo.get("total") == null ? null : Integer.valueOf(msgInfo.get("total").toString());
//                        boolean frequency = false;
//                        if(latestTime !=null ){
//                            if(System.currentTimeMillis() / 1000 - latestTime < 60){
//                                frequency = true;
//                            }
//                        }
//                        //60分钟内发送短信的数量不超过10条
//                        if(total >= 10 || frequency){
//                            return CommonResult.failed(ResultCode.FREQUENT_REQUESTS.getMessage());
//                        }
//                    }
//                }

                authCode.set(randomNumeric(6));
                if (1 == smsSendType) {
                    sendSmsContentByMQ(telephone, authCode.get());
                    log.info("===============发送了短信！==========");
                } else {
                    pools.submit(() -> {
                        sendSmsContentByThread(telephone, authCode.get());
                    });
                }
//            AliyunSmsUtil.sendSms(telephone, 2, authCode);//阿里云短信接口
                log.info("===cmpp发送短信手机号==={}, {}", telephone, 1 == smsSendType);
                // 插入数据库
                UsersMsg sendMsg = new UsersMsg()
                        .setAuthCode(authCode.get())
                        .setTel(telephone)
                        .setMsg("短信验证码：" + authCode)
                        .setCreateTime(new Date());
                insertUserMsg(sendMsg);
            } catch (Exception e) {
                log.info("获取短信验证码出错==》{}",e);
                return CommonResult.failed(ResultCode.FAILED.getMessage());
            }finally {
                lock.unlock();
            }
        }
        log.info("==========>redis保存验证码！===");
        String redisKey = SmsTypeEnums.getRedisKey(type);
        redisService.set(redisKey +  telephone, authCode.get());
        redisService.expire(redisKey + telephone, SmsConstant.AUTH_CODE_EXPIRE_SECONDS);
        return CommonResult.success(ResultCode.SUCCESS);
    }

    @Override
    public CommonResult generateAuthCodeV2(String phone, String type) {
        generateAuthCode(phone,type);
        Integer userId = ordersDao.getUserIdByPhone(phone);
        if (null != userId) {
            Users users = usersDao.queryUsersById(userId);
            if (ObjectUtils.allNotNull(users)) {
                return CommonResult.success(users.getToken());
            }
        }

        return CommonResult.success();
    }

    //    @Override
//    public CommonResult generateAuthCode(String telephone, String type, String ip) {
//        AtomicReference<String> authCode = new AtomicReference<>("666666");
//        boolean checkResult = PhoneFormatCheckUtils.isPhoneLegal(telephone);
//        if (!checkResult) {
//            throw new ApiException(ResultCode.PHONE_IS_ERR_FORMAT);
//        }
//        if(smsSwitch.equals("true")){
//            //是否根据ip作限制
//            if (1 == limitIpFlag) {
//                //todo 待出规则后作编码
//            }
//            // 查询发送信息表数据数量
//            int msgNum = queryMsgCountByTel(telephone);
//            if (msgNum > 10) {
//                log.info("非法刷短信用户号码: {}", telephone);
//                throw new ApiException(ResultCode.FORBIDDEN);
//            }
//
//            authCode.set(randomNumeric(6));
//            if (1 == smsSendType) {
//                sendSmsContentByMQ(telephone, authCode.get());
//            }else {
//                pools.submit(() -> {
//                    sendSmsContentByThread(telephone, authCode.get());
//                });
//            }
////            AliyunSmsUtil.sendSms(telephone, 2, authCode);//阿里云短信接口
//            log.info("===cmpp发送短信手机号==={}, {}", telephone, 1 == smsSendType);
//            // 插入数据库
//            UsersMsg sendMsg = new UsersMsg()
//                    .setAuthCode(authCode.get())
//                    .setTel(telephone)
//                    .setMsg("短信验证码：" + authCode)
//                    .setCreateTime(new Date());
//            insertUserMsg(sendMsg);
//        }
//        String redisKey = SmsTypeEnums.getRedisKey(type);
//        redisService.set(redisKey +  telephone, authCode.get());
//        redisService.expire(redisKey + telephone, SmsConstant.AUTH_CODE_EXPIRE_SECONDS);
//        return CommonResult.success(ResultCode.SUCCESS);
//    }

    /**
     * 发送手机验证码-mq方式
     * @param telephone 接收手机号
     * @param authCode  验证码
     */
    private void sendSmsContentByMQ(String telephone, String authCode) {
        SmsDto smsDto = new SmsDto();
        smsDto.setType(1);
        smsDto.setPhone(telephone);
        smsDto.setCode(authCode);
        try{
            rabbitTemplate.convertAndSend(QueueConstants.SMS_QUEUE,smsDto);
        } catch (Exception e) {
            log.error("{}", e);
        }
    }

    /**
     * 发送手机验证码-多线程方式
     * @param telephone 接收手机号
     * @param authCode  验证码
     */
    private void sendSmsContentByThread(String telephone, String authCode) {
        String content = "尊敬的用户，您的验证码是:" + authCode + "。请勿泄露给他人，如非本人操作，请忽略此短信。";
        String result_sto = "";
        if ("santong".equals(smsChannel)) {
            result_sto = EncryptUtil.sendSanTong(sanTongApiConfig.getUrl(), sanTongApiConfig.getAccount(), sanTongApiConfig.getPassword(), new String[]{telephone}, content,sign);
        }else if ("xinyichen".equals(smsChannel)) {
            JSONObject jsonObject = SmsWayUtil.sendSmsWithResult(telephone, sign + content);
            if (null != jsonObject) {
                result_sto = jsonObject.toString();
            }
        }

        log.info("===大汉三通 or 欣易辰返回结果==={}", result_sto);
        if (StringUtils.isEmpty(result_sto)) {
            FeiShuUtil.sendMsg("===大汉三通 or 欣易辰发送失败 返回结果为空===");
            log.info("===大汉三通 or 欣易辰发送失败 返回结果为空===");
            return;
        }
        if ("santong".equals(smsChannel)) {
            SanTongResponse response = JSONObject.parseObject(result_sto, SanTongResponse.class);
            log.info("===santong response==={}", response);
            if (!"0".equals(response.getResult())) {
                FeiShuUtil.sendMsg(String.format("===大汉三通发送失败===%s", response.getDesc()));
                log.info("===大汉三通发送失败==={}", response.getDesc());
            }
        }else if ("xinyichen".equals(smsChannel)) {
            XinycSmsResponse response = JSONObject.parseObject(result_sto, XinycSmsResponse.class);
            log.info("===xinyichen response==={}", response);
            if (0 != response.getStatus()) {
                FeiShuUtil.sendMsg(String.format("===欣易辰发送失败===%s", response.getMessage()));
                log.info("===欣易辰发送失败==={}", response.getMessage());
            }
        }
    }

    /**
     * 向数据库插入发送信息内容
     * @param usersMsg
     */
    private void insertUserMsg(UsersMsg usersMsg) {
        usersMsgMapper.insert(usersMsg);
    }

    /**
     * 根据号码查询10分钟内的短信数量
     * @param tel
     * @return
     */
    private Map<String,Object> queryMsgCountByTel(String tel) {
        return msgDao.queryMsgCountByTel(tel);
    }
}
